import React, { useEffect, useRef } from 'react';
import { useInterval, usePersistFn, useSafeState, useSetState } from 'ahooks';
import { addOnceEventListener } from '@/common/utils';
import { Context } from '../utils/store';

import styles from '../style/Provider.scss';

// 重试次数
const RETRY_NUMBER = 3;
// 重试间隔
const RETRY_INTERVAL = 2000;

const Provider = ({ data, status: statusProps, methods: methodsProps, volume: defaultVolume, children }) => {
  const [flvInstance, setFlvInstance] = useSafeState(null);
  const [hlsInstance, setHlsInstance] = useSafeState(null);
  const [dataIndex, setIndex] = useSafeState(0);
  const [status, setStatus] = useSetState({
    // 是否正在播放
    played: false,
    // 是否暂停
    paused: true,
    loading: true,
    volume: defaultVolume,
  });
  // 重试次数和时间
  const [retrySetting, setRetrySetting] = useSetState({ switch: false, number: RETRY_NUMBER, interval: RETRY_INTERVAL });

  const videoRef = useRef();
  const videoDom = videoRef.current;

  // 销毁
  const destroyHandle = usePersistFn(() => {
    if (videoDom) {
      videoDom.pause();
    }

    if (flvInstance) {
      try {
        flvInstance.unload();
        flvInstance.detachMediaElement();
        flvInstance.destroy();
      } catch (e) {
        // eslint-disable-next-line no-console
        console.warn(e);
      }

      setFlvInstance(null);
    }

    if (hlsInstance) {
      try {
        hlsInstance.destroy();
      } catch (e) {
        // eslint-disable-next-line no-console
        console.warn(e);
      }

      setHlsInstance(null);
    }
  });

  // 错误回调
  const onErrorHandle = () => {
    // 如果重试次数还有就继续重试
    if (retrySetting.number) return setRetrySetting({ switch: true });

    // setStatus({ loading: false, bufferLoading: false, create: false, destroy: true });
    //
    // return destroyHandle();
  };

  // 创建播放器实例
  const createPlayerInsHandle = usePersistFn(async () => {
    const { playUrl, protocolType } = data[dataIndex] || {};
    if (!playUrl) return;

    destroyHandle();

    videoRef.current.src = playUrl;

    if (protocolType === 'flv') {
      const { default: FlvJs } = await import(/* webpackChunkName: "mpegts.js" */'mpegts.js');
      if (FlvJs.isSupported()) {
        const ins = FlvJs.createPlayer({
          type: 'flv',
          url: playUrl,
        });
        ins.attachMediaElement(videoRef.current);
        ins.load();
        ins.on(FlvJs.Events.ERROR, onErrorHandle);

        setFlvInstance(ins);
      } else {
        setStatus({ ...status, loading: false });
      }
    } else if (protocolType === 'm3u8') {
      const { default: HlsJs } = await import(/* webpackChunkName: "hls.js" */'hls.js');
      if (HlsJs.isSupported()) {
        const ins = new HlsJs();

        ins.loadSource(playUrl);
        ins.attachMedia(videoRef.current);
        ins.on(HlsJs.Events.ERROR, onErrorHandle);

        setHlsInstance(ins);
      } else {
        setStatus({ ...status, loading: false });
      }
    } else {
      setStatus({ ...status, loading: false });
    }

    try {
      videoRef.current.load();
    } catch (e) {
      // eslint-disable-next-line no-console
      console.warn(e);
    }

    // ios退出全屏监听
    addOnceEventListener(videoRef.current, 'webkitendfullscreen', () => setStatus({ fullScreen: false }));
  });

  // 重试
  useInterval(() => {
    setRetrySetting({ switch: false, number: retrySetting.number - 1 });

    return createPlayerInsHandle();
  }, retrySetting.switch && retrySetting.number ? retrySetting.interval : undefined);

  // 根据索引创建播放器
  const createByIndexHandle = usePersistFn((index) => {
    const { playUrl } = data[index] || {};
    setStatus({ loading: !!playUrl, bufferLoading: false, create: false, destroy: !playUrl });

    setIndex(index);

    setRetrySetting({ switch: false, number: RETRY_NUMBER, interval: RETRY_INTERVAL });
    return createPlayerInsHandle();
  });

  // 设置数据索引
  const setDataIndexHandle = (v) => {
    if (dataIndex === v) return;

    return createByIndexHandle(v);
  };

  // 刷新操作
  const refreshHandle = () => createByIndexHandle(dataIndex);

  // 创建操作
  const createHandle = () => createByIndexHandle(0);

  // 音量设置
  const volumeHandle = (percentage) => {
    if (!videoDom) return;

    if (percentage) {
      videoDom.volume = percentage;
    } else {
      videoDom.volume = 0;
    }
  };
  // 开关音量
  const switchVolumeHandle = () => {
    if (!videoDom) return;
    const { volume } = videoDom;
    if (volume) return volumeHandle(0);

    return volumeHandle(defaultVolume);
  };

  // 播放操作
  const playHandle = async () => {
    if (!videoDom) return;
    try {
      await videoDom.play();
    } catch (e) {
      // eslint-disable-next-line no-console
      console.warn(e);
    }
    // return normalPlayHandle();
  };

  // 暂停操作
  const pauseHandle = () => {
    if (!videoDom) return;

    return videoDom.pause();
  };

  // video暂停回调事件
  const onVideoPauseHandle = () => {
    setStatus({
      paused: true,
      played: false,
    });
  };
  // video播放回调事件
  const onVideoPlayHandle = () => {
    setStatus({
      paused: false,
      played: true,
    });
  };
  // video音量改变回调事件
  const onVideoVolumechangeHandle = () => {
    const { volume } = videoDom;
    setStatus({ volume, muted: !volume });
  };
  // video可以播放时回调事件
  const onVideoCanPlayHandle = async () => {
    setStatus({ loading: false, bufferLoading: false, create: true, destroy: false });

    return playHandle();
  };

  // video缓冲中
  const onWaitingHandle = () => setStatus({ bufferLoading: true });

  const storeValue = {
    instance: videoDom,
    data: {
      index: dataIndex,
      list: data,
      setIndex: setDataIndexHandle,
    },
    status: {
      ...status,
      fullScreen: statusProps.fullScreen,
      ctrlVisible: statusProps.ctrlVisible,
    },
    methods: {
      // 销毁
      destroy: destroyHandle,
      // 创建
      create: createHandle,
      // 刷新
      refresh: refreshHandle,
      // 播放
      play: playHandle,
      // 暂停
      pause: pauseHandle,
      // 声音设置
      volume: volumeHandle,
      // 声音开关
      switchVolume: switchVolumeHandle,
      // 全屏
      fullScreen: methodsProps.fullScreen,
      // 退出全屏
      exitScreen: methodsProps.exitScreen,
    },
  };

  useEffect(() => destroyHandle, []);

  return (
    <Context.Provider value={storeValue}>
      <div className={styles.container}>
        {/* eslint-disable-next-line jsx-a11y/media-has-caption */}
        <video
          className={styles.video}
          ref={videoRef}
          webkit-playsinline="true"
          playsInline
          x5-playsinline="true"
          x-webkit-airplay="true"
          controls="controls"
          onPause={onVideoPauseHandle}
          onPlay={onVideoPlayHandle}
          onVolumeChange={onVideoVolumechangeHandle}
          onEnded={onErrorHandle}
          onCanPlay={onVideoCanPlayHandle}
          onWaiting={onWaitingHandle}
        />
      </div>
      {children}
    </Context.Provider>
  );
};

Provider.defaultProps = {
  status: {},
  methods: {},
  volume: 1,
};

export default Provider;
